/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package parse;

import drt.*;
import java.util.*;
import logic.Type;
import util.*;

/**
 *
 * @author phong
 */
public class CCGInternalNode extends CCGNode {
    
    // application
    static final String RULE_FA = "fa"; // OPT_FW application
    static final String RULE_BA = "ba"; // OPT_BW application

    // composition
    static final String RULE_FC = "fc"; // OPT_FW composition
    static final String RULE_BC = "bc"; // OPT_BW composition

    static final String RULE_FXC = "fxc"; // OPT_FW crossing composition
    static final String RULE_BXC = "bxc"; // OPT_BW crossing composition
    
    // generalized compostion
    static final String RULE_GFC = "gfc"; // generalized OPT_FW composition
    static final String RULE_GBC = "gbc"; // generalized OPT_BW composition

    static final String RULE_GFXC = "gfxc"; // generalized OPT_FW crossing composition
    static final String RULE_GBXC = "gbxc"; // generalized OPT_BW crossing composition

    // conjunction
    static final String RULE_CONJ = "conj"; // conjunction
    
    // type-raising
    static final String RULE_TR = "tr";
    
    // type changing
    static final String RULE_TC = "tc";
    
    
    String rule;
    CCGNode[] children;
        
    public CCGInternalNode(String rule, Category cat, DrtExpression sem, CCGNode[] children) {
        super(cat, sem);
        this.rule = rule;
        this.children = children;
        
        this.prob = 1;
        for (CCGNode child : children) {
            this.prob *= child.getProb();
            this.tokStartId = Math.min(this.tokStartId, child.tokStartId);
            this.tokEndId = Math.max(this.tokEndId, child.tokEndId);
        }
    }

    public String getRule() {
        return this.rule;
    }
    
    @Override
    public CCGNode[] getChildren() {
        return this.children;
    }
    
    @Override
    public List<CCGLexNode> getLexNodes() {
        List<CCGLexNode> lexNodes = this.children[0].getLexNodes();
        for (int i = 1; i < this.children.length; i++)
            lexNodes.addAll(this.children[i].getLexNodes());
        return lexNodes;
    }
    
    @Override
    public void updateTokIDs() {
        for (int i = 0; i < children.length; i++) {
            this.children[i].updateTokIDs();
        }
        
        if (this.children.length == 0)
            throw new Error("must have childnodes");
        
        Pair<Integer,Integer> tokIds = this.children[0].getTokIDs();
        this.tokStartId = tokIds.getFirst();
        this.tokEndId = tokIds.getSecond();
        
        for (int i = 1; i < this.children.length; i++) {
            tokIds = this.children[i].getTokIDs();
            this.tokStartId = Math.min(tokIds.getFirst(), this.tokStartId);
            this.tokEndId = Math.max(tokIds.getSecond(), this.tokEndId);            
        }
    }
    
    @Override
    public boolean equals(Object o) {
        if (o instanceof CCGInternalNode) {
            CCGInternalNode that = (CCGInternalNode)o;
            return this.cat.equals(that.cat) && this.sem.equals(that.sem);
        }
        else 
            return false;
    }
    
    @Override
    public int hashCode() {
        return this.cat.hashCode() * 17 + this.sem.hashCode();
    }
    
    @Override
    public String toString() {
        StringBuffer buffTabs = new StringBuffer();        
        for (int i = 0; i < tabs; i++) 
            buffTabs.append("\t");
        String strTabs = buffTabs.toString();
        
        StringBuffer buff = new StringBuffer();
        
        buff.append(strTabs).append("<internal>").append("\n");
        buff.append(strTabs).append(this.rule).append("\n");
        buff.append(strTabs).append(this.cat).append("\n");
        buff.append(strTabs).append(this.sem).append("\n");
        buff.append(strTabs).append(this.tokStartId).append("-").append(this.tokEndId).append("\n");
        
        tabs++;
        for (CCGNode node : this.children)
            buff.append(node.toString()).append("\n");
        tabs--;
        
        return buff.toString();
    }  
    
    @Override
    public void putInChart(Chart chart) {
        for (CCGNode child : this.children) 
            child.putInChart(chart);
        Cell cell = chart.getCell(this.tokStartId, this.tokEndId);
        cell.add(this);
    }
    
    @Override
    public void updateSem() {
        
        this.sem = null;
        
        this.prob = 1;
        for (CCGNode child : children) {
            if (child.getSem() == null)
                child.updateSem();
            this.prob *= child.getProb();
        }
        
        if (rule.equals(RULE_CONJ)) {
            
            try {
                // first case: and, or, but, ... : \v0 \v1 ( v0 ; v1) 
                Pair<List<DrtVariable>,DrtExpression> p = ((DrtLambdaExpression)this.children[1].sem).getComponents();
                List<DrtVariable> localVars = p.getFirst();
                DrtExpression localTerm1 = p.getSecond();

                p = ((DrtLambdaExpression)this.children[0].sem).getComponents();
                List<DrtVariable> globalVars = p.getFirst();
                globalVars.add(new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE));
                DrtExpression globalTerm = p.getSecond();
                
                DrtExpression localTerm2 = globalVars.get(globalVars.size()-1);
                localTerm2 = DrtApplicationExpression.make(localTerm2, new LinkedList<DrtExpression>(localVars));
                
                globalVars.addAll(localVars);
                this.sem = DrtLambdaExpression.make(globalVars, globalTerm);
                this.sem = new DrtApplicationExpression(this.sem, localTerm1);
                this.sem = new DrtApplicationExpression(this.sem, localTerm2);
                this.sem = this.sem.simplify();
            }            
            catch (Error e) {
                // second case: 
                try {
                    this.sem = new DrtApplicationExpression(this.children[0].sem, this.children[1].sem);
                }
                catch (Error e1) {
                    throw new Error("unknown conjunction type");
                }
            }
        }
        
        // > : c0@c1
        else if (rule.equals(RULE_FA)) 
            this.sem = new DrtApplicationExpression(children[0].sem, children[1].sem);
        
        // < : c1@c0
        else if (rule.equals(RULE_BA)) 
            this.sem = new DrtApplicationExpression(children[1].sem, children[0].sem);
        
        // >B , >Bx : \x. (c0 @ (c1 @ x))
        else if (rule.equals(RULE_FC) || rule.equals(RULE_FXC)) {  
            DrtVariable x = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
            this.sem = new DrtLambdaExpression(x,
                    new DrtApplicationExpression(
                        children[0].sem, 
                        new DrtApplicationExpression(children[1].sem, x)));
        }
            
        // <B , <Bx : \x. (c1 @ (c0 @ x))
        else if (rule.equals(RULE_BC) || rule.equals(RULE_BXC)) {  
            DrtVariable x = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
            this.sem = new DrtLambdaExpression(x,
                    new DrtApplicationExpression(
                        children[1].sem, 
                        new DrtApplicationExpression(children[0].sem, x)));
        }
        
        // >Bn , >Bxn : ...\x.c0(c1@x...)
        else if (rule.equals(RULE_GFC) || rule.equals(RULE_GFXC)) {
            Category X = ((ComplexCategory)children[0].getCat()).getLeft();
            Category Z = ((ComplexCategory)children[1].getCat()).getRight();
            Category T = this.cat.leftMostRemove(X).rightMostRemove(Z);
            int nx = T.numOfAllBasicCats() + 1;
            
            DrtExpression exp = children[1].sem;
            DrtVariable[] vars = new DrtVariable[nx];
            for (int i = 0; i < nx; i++) {
                DrtVariable v = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
                vars[i] = v;
                exp = new DrtApplicationExpression(exp,v);
            }
            exp = new DrtApplicationExpression(children[0].sem, exp);
            for (int i = nx-1; i >= 0; i-- ) {
                exp = new DrtLambdaExpression(vars[i], exp);
            }
            
            this.sem = exp;
        }

        // <Bn , <Bxn : ...\x.c1(c0@x...)
        else if (rule.equals(RULE_GBC) || rule.equals(RULE_GBXC)) {
            Category X = ((ComplexCategory)children[1].getCat()).getLeft();
            Category Z = ((ComplexCategory)children[0].getCat()).getRight();
            Category T = this.cat.leftMostRemove(X).rightMostRemove(Z);
            int nx = T.numOfAllBasicCats() + 1;
            
            DrtExpression exp = children[0].sem;
            DrtVariable[] vars = new DrtVariable[nx];
            for (int i = 0; i < nx; i++) {
                DrtVariable v = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
                vars[i] = v;
                exp = new DrtApplicationExpression(exp,v);
            }
            exp = new DrtApplicationExpression(children[1].sem, exp);
            for (int i = nx-1; i >= 0; i-- ) {
                exp = new DrtLambdaExpression(vars[i], exp);
            }
            
            this.sem = exp;
        }
        
        // type-raising
        else if (rule.equals(RULE_TR)) {
            DrtVariable v = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
            this.sem = new DrtLambdaExpression(
                    v, 
                    new DrtApplicationExpression(v, children[0].sem));
        }
        
        // type-changing
        else if (rule.equals(RULE_TC)) {
            this.sem = this.typeChanging(this.children[0].cat, this.cat, this.children[0].sem);
        }
        else 
            throw new Error("unknown rule " + this.rule);
        
        
        try {
            this.sem = this.sem.simplify();
        }
        catch (Error e) {
//            e.printStackTrace();
//            this.sem.simplify();
        }
        catch (Exception e1) {
//            e1.printStackTrace();
        }
    }
    
    public DrtExpression typeChanging(Category oCat, Category nCat, DrtExpression oSem) {        
        if (oCat.equals(BasicCategory.N) && nCat.equals(BasicCategory.NP))
            return this.N_NP(oSem);
        
        else if (oCat.equals(Category.IV) && nCat.equals(Category.VPMOD))
            return this.IV_VPMOD(oSem);
        
        else if (oCat.equals(Category.IV) && nCat.equals(Category.NP))
            return this.IV_NP(oSem);
        
        else if (oCat.equals(Category.IV) && nCat.equals(Category.ADJ))
            return this.IV_ADJ(oSem);
        
        else if (oCat.equals(Category.IV) && nCat.equals(Category.NPMOD))
            return this.IV_NPMOD(oSem);
        
        else if (oCat.equals(Category.S) && nCat.equals(Category.NPMOD))
            return this.S_NPMOD(oSem);
        
        else if (oCat.equals(Category.IV) && nCat.equals(Category.SMOD))
            return this.IV_SMOD(oSem);
        
        else if (oCat.equals(Category.S) && nCat.equals(Category.SMOD))
            return this.S_SMOD(oSem);
        
        else if (oCat.equals(Category.SMOD) && nCat.equals(Category.VPMOD))
            return this.SMOD_VPMOD(oSem);

        else if (oCat.equals(Category.TV)) {
            /* 
             * tv -> Cat := change(iv, Cat, oSem)
             * oSem = app(Old,lam(P,merge(drs([[]:X],[[]:pred(X,thing,n,12)]),app(P,X))))
             * 
             */
            DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
            DRSReferent x = new DRSReferent(Naming.getUniqueName("x0"));
            
            LinkedList<DRSReferent> refs = new LinkedList<DRSReferent>();
            refs.add(x);
            List<DRSCondition> conds = new LinkedList<DRSCondition>();
            conds.add(new DRSPredCondition("thing", x));
            DRS drs = new DRS(refs, conds);
            
            oSem = new DrtApplicationExpression(
                    oSem, 
                    new DrtLambdaExpression(
                        P, 
                        new DrtMergeExpression(
                            drs, 
                            new DrtApplicationExpression(P, x))));
            return this.typeChanging(Category.IV, nCat, oSem);
        }
        
        else if (oCat.equals(Category.NP) && nCat.equals(Category.NPNPMOD))
            return this.NP_NPNPMOD(oSem);
        
        else if (oCat.equals(Category.NP) && nCat.equals(Category.VPMOD))
            return this.NP_VPMOD(oSem);
        
        else if (oCat.equals(Category.SMOD) && nCat.equals(Category.SMOD))
            return oSem;
        
        else if (oCat.equals(Category.NP) && nCat.equals(Category.SMOD))
            return this.NP_SMOD(oSem);
        
        
        else 
            throw new Error("unknown type-changing from " + children[0].cat + " to " + this.cat);
    }
    
    public DrtExpression N_NP(DrtExpression oSem) {
        /*
        * change(n, np, Old, I, lam(P,merge(merge(drs([I:X],[]),app(Old,X)),app(P,X)))).
        * change(n, pn, Old, I, lam(P,alfa(nam,merge(drs([I:X],[]),app(Old,X)),app(P,X)))).
        */
        DrtVariable p = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DRSReferent x = new DRSReferent(Naming.getUniqueName("x0"));
        DRS f1 = new DRS(Arrays.asList(x), new LinkedList<DRSCondition>());
        DrtApplicationExpression f2 = new DrtApplicationExpression(oSem, x);
        DrtApplicationExpression f3 = new DrtApplicationExpression(p, x);

        DrtExpression nSem;
        if (children[0].getCat().getFeature().equals("nam"))
            nSem = new DrtLambdaExpression(
                    p, 
                    new DrtAlphaExpression(
                        new DrtMergeExpression(f1, f2), 
                        f3));
        else
            nSem = new DrtLambdaExpression(
                    p, 
                    new DrtMergeExpression(
                        new DrtMergeExpression(f1, f2), 
                        f3));
        return nSem;
    }
    
    public DrtExpression IV_VPMOD(DrtExpression oSem) {
        /*
        * iv -> vpmod
        * //lam(X,lam(Q,lam(E,merge(app(app(X,Q),E),app(app(Old,lam(P,merge(drs([I:Y],[]),app(P,Y)))),lam(E,drs([],[])))))))
        * \v0\v1\v2
        *         (v1 @ \v3
        *                 ( \T ( (Old@\P.(P@v3)@\x.T)@((v0@\v4(v4@v3))@v2)
        */
        DrtVariable v0 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable v1 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable v2 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable v3 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable v4 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable T = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable x = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);

        DrtExpression nSem = new DrtLambdaExpression(
                v0, 
                new DrtLambdaExpression(
                    v1, 
                    new DrtLambdaExpression(
                        v2, 
                        new DrtApplicationExpression(
                            v1, 
                            new DrtLambdaExpression(
                                v3, 
                                new DrtApplicationExpression(
                                    new DrtLambdaExpression(
                                        T, 
                                        new DrtApplicationExpression(
                                            new DrtApplicationExpression(
                                                oSem, 
                                                new DrtLambdaExpression(
                                                    P, 
                                                    new DrtApplicationExpression(P, v3))), 
                                            new DrtLambdaExpression(x, T))), 
                                    new DrtApplicationExpression(
                                        new DrtApplicationExpression(
                                            v0, 
                                            new DrtLambdaExpression(v4, new DrtApplicationExpression(v4, v3))), 
                                        v2)))))));
        return nSem;
    }

    public DrtExpression IV_NP(DrtExpression oSem) {
        /*
            * iv -> np
            */
        // lam(P,merge(drs([[]:X],[[]:pred(X,thing,n,12)]),app(P,X)))
        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DRSReferent X = new DRSReferent(Naming.getUniqueName("x0"));

        List<DRSReferent> refs = new LinkedList<DRSReferent>();
        refs.add(X);
        List<DRSCondition> conds = new LinkedList<DRSCondition>();
        List<DrtEntity> args = new LinkedList<DrtEntity>();
        args.add(X);
        conds.add(new DRSPredCondition("thing", args));
        DRS drs = new DRS(refs, conds);

        DrtExpression nSem = new DrtApplicationExpression(
                oSem,
                new DrtLambdaExpression(
                    P, 
                    new DrtMergeExpression(
                        drs, 
                        new DrtApplicationExpression(P, X))));
        return nSem;
    }

    public DrtExpression IV_ADJ(DrtExpression oSem) {
        /*
            * iv -> adj
            * lam(P,lam(X,app(app(Old,lam(Q,merge(app(Q,X),app(P,X)))),lam(E,drs([],[[]:pred(E,event,n,1)])))))).
            */

        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable Q = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable X = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtEntityVariable E = new DrtEntityVariable(Naming.getUniqueName("v0"));

        return new DrtLambdaExpression(
                P, 
                new DrtLambdaExpression(
                    X, 
                    new DrtApplicationExpression(
                        new DrtApplicationExpression(
                            oSem, 
                            new DrtLambdaExpression(
                                Q, 
                                new DrtMergeExpression(
                                    new DrtApplicationExpression(Q, X), 
                                    new DrtApplicationExpression(P, X)))),
                        new DrtLambdaExpression(
                            E, 
                            new DRS(new LinkedList<DRSReferent>(), new LinkedList<DRSCondition>())))));
    }

    public DrtExpression IV_NPMOD(DrtExpression oSem) {
        /*
        * iv -> npmod
        *      lam(Q,
        *          lam(P,
        *              app(Q,
        *                  lam(X,
        *                      app(
        *                          app(Old,lam(R,merge(app(R,X),app(P,X))))
        *                          lam(E, drs()),
        * ))))).
        */

        DrtVariable Q = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable X = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtEntityVariable E = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtVariable R = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);

        return new DrtLambdaExpression(
                Q, 
                new DrtLambdaExpression(
                    P,
                    new DrtApplicationExpression(
                        Q, 
                        new DrtLambdaExpression(
                            X, 
                            new DrtApplicationExpression(
                                new DrtApplicationExpression(
                                    oSem, 
                                    new DrtLambdaExpression(
                                        R,
                                        new DrtMergeExpression(
                                            new DrtApplicationExpression(R, X), 
                                            new DrtApplicationExpression(P, X)))),
                                new DrtLambdaExpression(E, new DRS(new LinkedList<DRSReferent>(), new LinkedList<DRSCondition>())))))));
    }

    public DrtExpression S_NPMOD(DrtExpression oSem) {
        /*
        * s -> npmod
        * lam(Q,lam(P,app(Q,lam(X,merge(app(P,X),app(Old,lam(E,drs([],[[]:pred(E,event,n,1),[]:rel(E,X,rel,0)]))))))))
        */
        DrtVariable Q = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable X = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtEntityVariable E = new DrtEntityVariable(Naming.getUniqueName("v0"));

        List<DRSCondition> conds = new LinkedList<DRSCondition>();
        List<DrtEntity> args = new LinkedList<DrtEntity>();
        args.add(E); args.add(X);
        conds.add(new DRSPredCondition("rel", args));
        DRS drs = new DRS(new LinkedList<DRSReferent>(), conds);

        return new DrtLambdaExpression(
                Q, 
                new DrtLambdaExpression(
                    P, 
                    new DrtApplicationExpression(
                        Q, 
                        new DrtLambdaExpression(
                            X, 
                            new DrtMergeExpression(
                                new DrtApplicationExpression(P, X), 
                                new DrtApplicationExpression(
                                    oSem,
                                    new DrtLambdaExpression(
                                        E, 
                                        drs)))))));
    }

    public DrtExpression IV_SMOD(DrtExpression oSem) {
        /*
        * iv -> smod
        * lam(S,lam(E,merge(app(app(Old,lam(P,merge(drs([I:X],[]),app(P,X)))),lam(Y,drs([],[])),app(S,E))))
        */
        DrtVariable S = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable E = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable P = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable x0 = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DRSReferent x = new DRSReferent(Naming.getUniqueName("x0"));

        List<DRSReferent> refs = new LinkedList<DRSReferent>();
        refs.add(x);
        DRS drs = new DRS(refs, new LinkedList<DRSCondition>());

        return new DrtLambdaExpression(
                S, 
                new DrtLambdaExpression(
                    E, 
                    new DrtMergeExpression(
                        new DrtApplicationExpression(
                            new DrtApplicationExpression(
                                oSem, 
                                new DrtLambdaExpression(
                                    P, 
                                    new DrtMergeExpression(
                                        drs, 
                                        new DrtApplicationExpression(P, x)))), 
                            new DrtLambdaExpression(
                                x0, 
                                new DRS(new LinkedList<DRSReferent>(), new LinkedList<DRSCondition>()))), 
                        new DrtApplicationExpression(S, E))));
    }

    public DrtExpression S_SMOD(DrtExpression oSem) {
        /*
        * s -> smod
        * lam(S,lam(E,merge(app(Old,lam(E,drs([],[[]:pred(E,event,n,1)]))),app(S,E))))).
        */
        DrtVariable S = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable E = new DrtEntityVariable(Naming.getUniqueName("v0"));
        return new DrtLambdaExpression(
                S, 
                new DrtLambdaExpression(
                    E, 
                    new DrtMergeExpression(
                        new DrtApplicationExpression(
                            oSem, 
                            new DrtLambdaExpression(
                                E, 
                                new DRS(new LinkedList<DRSReferent>(), new LinkedList<DRSCondition>()))), 
                        new DrtApplicationExpression(S, E))));
    }    
    
    public DrtExpression NP_NPNPMOD(DrtExpression oSem) {
        /*
         * np -> npnpmod
         * lam(M,app(M,Old)))
         */
        DrtVariable M = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        return new DrtLambdaExpression(
                        M, 
                        new DrtApplicationExpression(
                            M, 
                            oSem));
    }
    
    public DrtExpression SMOD_VPMOD(DrtExpression oSem) {
        /*
         * smod -> vpmod
         * lam(V,lam(N,app(Old,app(V,N))))
         */
        DrtVariable V = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable N = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        return new DrtLambdaExpression(
                V, 
                new DrtLambdaExpression(
                    N, 
                    new DrtApplicationExpression(
                        oSem, 
                        new DrtApplicationExpression(V, N))));
    }
    
    public DrtExpression NP_VPMOD(DrtExpression oSem) {
        /*
         * np -> vpmod
         * lam(V,lam(N,lam(E,app(app(V,N),lam(X,merge(app(Old,lam(Y,drs([],[[]:rel(X,Y,rel,0)]))),app(E,X)))))))
         */
        DrtVariable V = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable N = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable E = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable X = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtEntityVariable Y = new DrtEntityVariable(Naming.getUniqueName("v0"));
        
        DRS drs = new DRS();
        drs.getConds().add(new DRSPredCondition("rel", X, Y));
        
        return new DrtLambdaExpression(
                V, 
                new DrtLambdaExpression(
                    N, 
                    new DrtLambdaExpression(
                        E, 
                        new DrtApplicationExpression(
                            new DrtApplicationExpression(V, N), 
                            new DrtLambdaExpression(
                                X, 
                                new DrtMergeExpression(
                                    new DrtApplicationExpression(
                                        oSem, 
                                        new DrtLambdaExpression(Y, drs)), 
                                    new DrtApplicationExpression(E, X)))))));
    }
    
    public DrtExpression NP_SMOD(DrtExpression oSem) {
        /*
         * np -> smod
         * lam(S,lam(E,app(S,lam(X,merge(app(Old,lam(Y,drs([],[[]:rel(X,Y,rel,0)]))),app(E,X))))))
         */
        
        DrtVariable S = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtVariable E = new DrtVariable(Naming.getUniqueName("v0"), Type.UNKNOWN_TYPE);
        DrtEntityVariable X = new DrtEntityVariable(Naming.getUniqueName("v0"));
        DrtEntityVariable Y = new DrtEntityVariable(Naming.getUniqueName("v0"));
        
        DRS drs = new DRS();
        drs.getConds().add(new DRSPredCondition("rel", X, Y));
        
        return new DrtLambdaExpression(
                S, 
                new DrtLambdaExpression(
                    E, 
                    new DrtApplicationExpression(
                        S, 
                        new DrtLambdaExpression(
                            X, 
                            new DrtMergeExpression(
                                new DrtApplicationExpression(
                                    oSem, 
                                    new DrtLambdaExpression(Y, drs)), 
                                new DrtApplicationExpression(E, X))))));
    }
}
